package com.brotherly.framework.http;

import java.io.StringWriter;

import com.brotherly.framework.event.EventService;
import com.brotherly.framework.timer.TimerListener;
import com.brotherly.framework.timer.TimerService;
import com.brotherly.framework.transaction.TransactionConstant;
import com.brotherly.framework.transaction.TransactionServiceHost;
import com.brotherly.util.JSonSax;

public class NetworkWatcher implements TimerListener
{
    protected static NetworkWatcher pthis;

    public static NetworkWatcher getInstance()
    {
        if (pthis == null)
            pthis = new NetworkWatcher();

        return pthis;
    }

    protected int timerStub = -1;

    protected long uploadBytes = 0;
    protected long downloadBytes = 0;

    protected long completeTasks = 0;
    protected long failedTasks = 0;
    protected long exceptionTasks = 0;

    protected long currentUploadBytes = 0;
    protected long currentDownloadBytes = 0;

    protected long currentCompleteTasks = 0;
    protected long currentFailedTasks = 0;
    protected long currentExceptionTasks = 0;

    protected long prevCompleteTasksFactor = 0;
    protected long prevFailedTasksFactor = 0;
    protected long prevExceptionTasksFactor = 0;

    public NetworkWatcher()
    {}

    public void start()
    {
        if (timerStub != -1)
            return;

        TimerService timerServ = (TimerService) TransactionServiceHost.getInstance().getService(TimerService.description);

        try
        {
            timerStub = timerServ.startTimer(this, 60000);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public void stop()
    {
        if (timerStub == -1)
            return;

        TimerService timerServ = (TimerService) TransactionServiceHost.getInstance().getService(TimerService.description);

        try
        {
            timerServ.cancel(timerStub);
            timerStub = -1;
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

    }

    public synchronized void reportUpload(int bytes)
    {
        currentUploadBytes += bytes;
    }

    public synchronized void reportDownload(int bytes)
    {
        currentDownloadBytes += bytes;
    }

    public synchronized void reportCompleteTask()
    {
        ++currentCompleteTasks;
    }

    public synchronized void reportFailedTask()
    {
        ++currentFailedTasks;
    }

    public synchronized void reportExceptionTask()
    {
        ++currentExceptionTasks;
    }

    @Override
    public synchronized void onTimer()
    {
        EventService eventServ = (EventService) TransactionServiceHost.getInstance().getService(EventService.description);

        uploadBytes += currentUploadBytes;
        downloadBytes += currentDownloadBytes;

        completeTasks += currentCompleteTasks;
        failedTasks += currentFailedTasks;
        exceptionTasks += currentExceptionTasks;

        float score = ((currentFailedTasks + prevFailedTasksFactor) + (currentExceptionTasks + prevExceptionTasksFactor))
                / (float) ((currentFailedTasks + prevFailedTasksFactor) + (currentExceptionTasks + prevExceptionTasksFactor) + (currentCompleteTasks + prevCompleteTasksFactor));

        float failed_score = (currentFailedTasks + prevFailedTasksFactor)
                / (float) ((currentFailedTasks + prevFailedTasksFactor) + (currentExceptionTasks + prevExceptionTasksFactor) + (currentCompleteTasks + prevCompleteTasksFactor));

        float exception_score = (currentExceptionTasks + prevExceptionTasksFactor)
                / (float) ((currentFailedTasks + prevFailedTasksFactor) + (currentExceptionTasks + prevExceptionTasksFactor) + (currentCompleteTasks + prevCompleteTasksFactor));

        try
        {
            StringWriter writer = new StringWriter();
            JSonSax sax = new JSonSax(writer);

            sax.startMap();

            sax.writeString("uploadBytes");
            sax.writeLong(uploadBytes);

            sax.writeString("downloadBytes");
            sax.writeLong(downloadBytes);

            sax.writeString("currentFailedTasks");
            sax.writeLong(currentFailedTasks);

            sax.writeString("completeTasks");
            sax.writeLong(completeTasks);

            sax.writeString("currentExceptionTasks");
            sax.writeLong(currentExceptionTasks);

            sax.writeString("score");
            sax.writeDouble(score);

            sax.endMap();

            sax.flush();

            eventServ.signEvent(TransactionConstant.event_network_info, writer.toString(), null);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        if (score > 0.7)
        {
            try
            {
                StringWriter writer = new StringWriter();
                JSonSax sax = new JSonSax(writer);

                sax.startMap();

                sax.writeString("score");
                sax.writeDouble(score);

                sax.writeString("failed_score");
                sax.writeDouble(failed_score);

                sax.writeString("exception_score");
                sax.writeDouble(exception_score);

                sax.endMap();

                sax.flush();

                eventServ.signEvent(TransactionConstant.event_network_warning, writer.toString(), null);
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }

        prevCompleteTasksFactor = (int) ((prevCompleteTasksFactor + currentCompleteTasks) * 0.6);
        prevFailedTasksFactor = (int) ((prevFailedTasksFactor + currentFailedTasks) * 0.3);
        prevExceptionTasksFactor = (int) ((prevExceptionTasksFactor + currentExceptionTasks) * 0.5);

        currentUploadBytes = 0;
        currentDownloadBytes = 0;

        currentCompleteTasks = 0;
        currentFailedTasks = 0;
        currentExceptionTasks = 0;
    }

    private boolean isOnTask = false;

    @Override
    public boolean isOnTask()
    {
        return this.isOnTask;
    }

    @Override
    public void setOnTask(boolean ontask)
    {
        this.isOnTask = ontask;
    }
}
